package com.yeskery.nut.transaction;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * JDBC事务
 * @author sprout
 * @version 1.0
 * 2022-08-27 13:33
 */
public class JdbcTransaction implements Transaction {
    /** 日志对象 */
    private static final Logger logger = Logger.getLogger(JdbcTransaction.class.getName());
    /** 连接对象 */
    private Connection connection;
    /** 数据源对象 */
    private DataSource dataSource;
    /** 事务隔离级别 */
    private TransactionIsolationLevel level;
    /** 是否自动提交 */
    private boolean autoCommit;
    /** 是否跳过关闭连接时设置自动提交 */
    private boolean skipSetAutoCommitOnClose;

    /**
     * 构建一个JDBC事务对象
     * @param dataSource 数据源对象
     * @param level 事务隔离级别
     * @param autoCommit 是否自动提交
     */
    public JdbcTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit) {
        this(dataSource, level, autoCommit, false);
    }

    /**
     * 构建一个JDBC事务对象
     * @param dataSource 数据源对象
     * @param level 事务隔离级别
     * @param autoCommit 是否自动提交
     * @param skipSetAutoCommitOnClose 是否跳过关闭连接时设置自动提交
     */
    public JdbcTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit, boolean skipSetAutoCommitOnClose) {
        this.dataSource = dataSource;
        this.level = level;
        this.autoCommit = autoCommit;
        this.skipSetAutoCommitOnClose = skipSetAutoCommitOnClose;
    }

    /**
     * 构建一个JDBC事务对象
     * @param connection 连接对象
     */
    public JdbcTransaction(Connection connection) {
        this.connection = connection;
    }

    @Override
    public Connection getConnection() {
        if (connection == null) {
            openConnection();
        }

        return connection;
    }

    @Override
    public void commit() {
        try {
            if (connection != null && !connection.getAutoCommit()) {
                connection.commit();
            }
        } catch (SQLException e) {
            throw new TransactionException("Transaction Execute Fail.", e);
        }
    }

    @Override
    public void rollback() {
        try {
            if (connection != null && !connection.getAutoCommit()) {
                connection.rollback();
            }
        } catch (SQLException e) {
            throw new TransactionException("Transaction Execute Fail.", e);
        }
    }

    @Override
    public void close() {
        try {
            if (connection != null) {
                resetAutoCommit();
                connection.close();
            }
        } catch (SQLException e) {
            throw new TransactionException("Transaction Execute Fail.", e);
        }
    }

    /**
     * 设置是否自动提交
     * @param autoCommit 是否自动提交
     */
    public void setAutoCommit(boolean autoCommit) {
        try {
            if (connection.getAutoCommit() != autoCommit) {
                connection.setAutoCommit(autoCommit);
            }

        } catch (SQLException e) {
            throw new TransactionException("Transaction Execute Fail.", e);
        }
    }

    /**
     * 重新设置是否自动提交
     */
    public void resetAutoCommit() {
        try {
            if (!skipSetAutoCommitOnClose && !connection.getAutoCommit()) {
                connection.setAutoCommit(true);
            }
        } catch (SQLException e) {
            if (logger.isLoggable(Level.FINEST)) {
                logger.logp(Level.FINEST, JdbcTransaction.class.getName(), "resetAutoCommit",
                        "Transaction Execute Fail.", e);
            }
        }
    }

    /**
     * 获取一个连接对象
     */
    public void openConnection() {
        try {
            connection = dataSource.getConnection();
            if (level != null && level != TransactionIsolationLevel.DEFAULT) {
                connection.setTransactionIsolation(level.getLevel());
            }

            setAutoCommit(autoCommit);
        } catch (SQLException e) {
            throw new TransactionException("Transaction Execute Fail.", e);
        }
    }
}
